#pragma once

#include <queue>
#include "Cond.hpp"
#include "Mutex.hpp"

using namespace MutexModule;
using namespace CondModule;

const int gcap = 5;

template <class T>
class BlockQueue
{
public:
    BlockQueue(int cap = gcap)
        : _cap(cap), _c_sleep(0), _p_sleep(0)
    {}

    //判断阻塞队列为空
    bool IsEmpty()
    {
        return _bq.empty();
    }

    //判断阻塞队列为满
    bool IsFull()
    {
        return _bq.size() >= _cap;
    }

    //生产者入队列
    void Entry(const T& in)
    {
        _mutex.Lock();
        //notice: 

        while(IsFull())
        {
            _p_sleep++;
            _full_cond.Wait(_mutex);
            _p_sleep--;
        }

        _bq.push(in);

        if(_c_sleep > 0)
            _empty_cond.Signal();
        _mutex.Unlock();
    }

    //消费者从队列中拿
    T Pop()
    {
        T data;
        _mutex.Lock();
        while(IsEmpty())
        {
            _c_sleep++;
            _empty_cond.Wait(_mutex);
            _c_sleep++;
        }
        data = _bq.front();
        _bq.pop();

        if(_p_sleep > 0)
            _full_cond.Signal();

         _mutex.Unlock();
         
        return data; 
    }


    ~BlockQueue()
    {}
private:
    // 底层容器
    std::queue<int> _bq;
    // BlockQueue的容量
    int _cap;

    // 保护BlockQueue的一把锁
    Mutex _mutex;

    // 两个条件变量: 生产者， 消费者
    Cond _full_cond;
    Cond _empty_cond;

    // 生产者和消费者的休眠个数
    int _c_sleep;
    int _p_sleep;
};
